#!/usr/bin/env node
const { exec } = require("child_process");

const os = require("os");
const fs = require("fs");
const path = require("path");

const { promisify } = require("util");
const readdir = promisify(fs.readdir);
const stat = promisify(fs.stat);

const { createWriteStream, createReadStream } = require("fs");

const archiver = require("archiver");
const inquirer = require("inquirer");

const Spinner = require("cli-spinner").Spinner;
// 创建一个新的 Spinner 实例
const spinner1 = new Spinner("正在打包... %s");
spinner1.setSpinnerString("|/-\\");

// 启动 inquirer
inquirer
  // 交互内容
  .prompt([
    {
      type: "input",
      message: "请输入可执行的打包命令(默认为yarn build)",
      name: "buildProcessStr",
      default: "yarn build",
    },
    {
      type: "confirm",
      message: "是否对打包后的文件进行压缩？",
      name: "isCompress",
    },
    {
      type: "input",
      message: "当前项目下已打包的文件的相对路径",
      name: "distRelativePath",
      default: "dist",
      when: (answers) => {
        return answers?.isCompress;
      },
    },
    {
      type: "list",
      message: "压缩文件输出位置选择:",
      name: "processFilePosition",
      choices: [
        {
          value: 1,
          name: "当前项目根目录",
        },
        {
          value: 2,
          name: "桌面上",
        },
      ],
      when: (answers) => {
        return answers?.isCompress;
      },
    },
  ])
  // 收集用户答案后的回调，会以键值对的方式存储在这里
  .then(async (answers) => {
    console.log(answers);
    const {
      buildProcessStr,
      isCompress,
      distRelativePath,
      processFilePosition,
    } = answers;
    try {
      if (buildProcessStr) {
        spinner1.start();
        const res = await execbuildProcess(buildProcessStr); // 打包成功

        if (res && isCompress) {
          processFn(distRelativePath, processFilePosition);
        }
      }
    } catch (err) {
      console.log(err);
    } finally {
      spinner1.stop();
    }
  })
  // 捕获错误的回调
  .catch((error) => {
    console.log(error);
  });

const processFn = (distRelativePath, processFilePosition) => {
  // 使用示例  将 dist文件 压缩到桌面上
  const folderToZip = path.join(process.cwd(), distRelativePath); // 要压缩的文件夹路径

  let zipFileName;
  if (processFilePosition == 1) {
    zipFileName = path.join(process.cwd(), "dist.zip"); // 压缩包名称
  }
  if (processFilePosition == 2) {
    zipFileName = path.join(os.homedir() + "\\Desktop", "dist.zip"); // 压缩包名称
  }

  zipFolder(folderToZip, zipFileName).catch((err) =>
    console.error("压缩失败:", err)
  );
};

// 执行打包命令函数
const execbuildProcess = (buildProcessStr) => {
  return new Promise((reslove, reject) => {
    exec(buildProcessStr, (error, stdout, stderr) => {
      if (error) {
        console.log(error);
        reject(false);
        return;
      }

      console.log(`stdout: ${stdout}`);
      console.error(`stderr: ${stderr}`);
      reslove(true);
    });
  });
};

// 压缩一个文件夹
async function zipFolder(folderPath, zipFilePath) {
  const output = createWriteStream(zipFilePath);
  const archive = archiver("zip", { zlib: { level: 9 } });

  output.on("close", () => console.log(`压缩完成: ${zipFilePath}`));
  output.on("error", (err) => console.error("压缩失败:", err));
  archive.on("error", (err) => console.error("压缩失败:", err));

  archive.pipe(output);

  const addFiles = async (dir) => {
    const files = await readdir(dir);
    for (const file of files) {
      const filePath = `${dir}/${file}`;
      const stats = await stat(filePath);
      // 判断是否是文件夹
      if (stats.isDirectory()) {
        await addFiles(filePath);
      } else {
        // 是文件  则读取文件内容 获取文件流
        const stream = createReadStream(filePath);
        archive.append(stream, { name: filePath.replace(folderPath, "") });
      }
    }
  };

  await addFiles(folderPath);
  await archive.finalize();
}
